package com.xiezc.dht.entity;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.xiezc.dht.model.BeObject;
import com.xiezc.dht.model.BeString;
import com.xiezc.dht.util.Const;
import com.xiezc.dht.util.XUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Data
@Slf4j
public class Node {

    /**
     * 所有的Node全部放在这个对象中
     */
    private static Cache<BeString, Node> nodeCaches = CacheBuilder
            .newBuilder()
            .expireAfterAccess(3 * Const.deadNodeTimeSec, TimeUnit.MILLISECONDS)
            .build();

    /**
     * 取出缓存, 如果没有则新建. 新建的对象不会放入缓存
     *
     * @param id
     * @param socketAddress
     * @return
     */
    public static Node createNode(BeString id, InetSocketAddress socketAddress) {
        Node node = nodeCaches.getIfPresent(id);
        if (node == null) {
            node = new Node(id);
        } else {
            node.updateTime();
        }
        node.init(socketAddress);
        Bucket bucket = Const.routerTable.getBucket(node.getBK());
        bucket.put(node);
        return node;
    }

    /**
     * 放入缓存
     *
     * @param node
     */
    public static void putCahce(Node node) {
        nodeCaches.put(node.getId(), node);
    }

    private BeString id;

    private InetSocketAddress socketAddress;

    private long time;

    private int BK;

    private List<BeObject> values;

    private Bucket bucket;

    private Node(BeString id) {
        this.id = id;
        BK = XUtil.distanceK(Const.thisId, id);
        values = new ArrayList<>();
    }

    private void init(InetSocketAddress socketAddress) {
        time = System.currentTimeMillis();

        //相等那就ｏｋ不用动
        if (socketAddress.equals(this.socketAddress)) {
            return;
        } else {
            //不相等，　获得新的地址的ｖａｌｕｅｓ
            byte[] cip = getIpValues(socketAddress);
            if (this.socketAddress != null) {
                //不是空的先去掉旧的
                byte[] cip1 = getIpValues(this.socketAddress);
                values.remove(new BeString(cip1));
            }
            values.add(new BeString(cip));
        }
        this.socketAddress = socketAddress;
    }

    private byte[] getIpValues(InetSocketAddress socketAddress) {
        byte[] address = socketAddress.getAddress().getAddress();
        int port = socketAddress.getPort();
        byte port1 = (byte) (port >>> 8);
        byte port2 = (byte) port;
        byte[] cip = new byte[6];
        cip[0] = address[0];
        cip[1] = address[1];
        cip[2] = address[2];
        cip[3] = address[3];
        cip[4] = port1;
        cip[5] = port2;
        return cip;
    }

    public boolean isAlive() {
        return System.currentTimeMillis() - time < Const.deadNodeTimeSec;
    }

    public void updateTime() {
        time = System.currentTimeMillis();
    }


}